#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <fcntl.h>
#include "FTHeader.h"
#include "clientTask.h"
#include "TCPUtils.h"
const char *client_path = ".";

static int send_request(TCPInfo *info, int sock_fd) {
	char request[128];
	ssize_t ret;

	snprintf(request, sizeof(request),"GET:%s\r\n\r\n", info->filename);
	ret = send(sock_fd, request, strlen(request), 0);
	if (ret < 0) {
		perror("send");
		return -1;
	}
	return 0;
}

static int get_status(FTHeader *response_header) {
	if (response_header->data[0] == 'S') {
		return 0;
	} else {
		return -1;
	}
}

static size_t init_file(FTHeader *response_header, int fd) {
	char *tmp = strstr(response_header->data, "\r\n\r\n");
    if (tmp == NULL) {
        return -1;
    }
	ssize_t ret = 0;
	if (tmp - response_header->data + 4 == response_header->pos) {
		printf("header no other data!\n");
		return 0;
	} else {
		ret = write(fd, tmp + 4, response_header->pos - (tmp - response_header->data + 4));
		if (ret < 0) {
			perror("write");
			return -1;
		}
		printf("header other data: %ld\n", ret);
		return ret;
	}
}

static void receive_data(int sock_fd, int fd) {
	char buf[1024];
	ssize_t ret;

	ret = recv(sock_fd, buf, sizeof(buf), 0);
	while (ret) {
		if (ret < 0) {
			perror("rcv");
			break;
		}
		ret = write(fd, buf, ret);
		if (ret < 0) {
			perror("loop write:");
			break;
		}
		ret = recv(sock_fd, buf, sizeof(buf), 0);
	}
	printf("receive over!\n");
}

int clientDownTask(TCPInfo *info) {
	FTHeader *header = NULL;
	int code = 0;
	int status;

	// 1. 连接服务器
	int sock_fd = initClient(info->hostname, info->port);
	if (sock_fd < 0) {
		fprintf(stderr, "initClient failed!\n");
		return -1;
	}
	// 2. 发送请求
	if (send_request(info, sock_fd) < 0) {
		code = -1;
		goto out2;
	}
	// 3. 创建响应头
	FTHeader *response_header = createFTHeader(MAX_RESPONSE_HEADER);
	if (response_header == NULL) {
		fprintf(stderr, "Response error!\n");
		code = -1;
		goto out2;
	}
	// 4. 接收响应头
	status = initFTHeader(response_header, sock_fd, "\r\n\r\n");
	if (status < 0) {
		fprintf(stderr, "response_header format invalid!\n");
		code = -2;
		goto out1;
	}
	// 7. 解析响应是否成功
	if (get_status(response_header) < 0) {
		fprintf(stderr, "response failed!\n");
		code = -2;
		goto out1;
	}

	char filename[128];
	snprintf(filename, sizeof(filename), "%s/%s",client_path, info->filename);
	int fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, 0666);
	if (fd < 0) {
		perror("open");
		code = -2;
		goto out1;
	}
	size_t t;
	t = init_file(response_header, fd);
	if (t < 0) {
		fprintf(stderr, "write response failed!\n");
		code = -3;
		goto out;
	}
	receive_data(sock_fd, fd);
out:
	close(fd);
out1:
	releaseFTHeader(header);
out2:
	close(sock_fd);
	return code;
}

int clientUploadTask(TCPInfo *info) {
	if (info == NULL)
		return -1;
	return 0;
}

int clientListTask(TCPInfo *info) {
	if (info == NULL)
		return -1;
	return 0;
}

int clientShowHelp(TCPInfo *info) {
	printf("help : display help info\n");
	printf("list : get file list of server\n");
	printf("get  : get <file>\n");
	printf("put  : put <file>\n");
	printf("quit : quit the client\n");
	return 0;
}

/**
 * typedef struct {				// 任务信息
	char hostname[64];
	uint16_t port;
	char *filename;
}TCPInfo;
 * @param hostname
 * @param port
 * @param filename
 * @return
 */
TCPInfo *createTCPInfo(const char *hostname, uint16_t port, const char *filename) {
	TCPInfo *info = (TCPInfo *) malloc(sizeof(TCPInfo));
	if (info == NULL) {
		fprintf(stderr, "tcp info malloc failed!\n");
		return NULL;
	}
	info->port = port;
	strncpy(info->hostname, hostname, sizeof(info->hostname));
	if (filename) {
		info->filename = (char *) malloc(sizeof(char ) * (strlen(filename) + 1));
		strcpy(info->filename, filename);
	} else {
		info->filename = NULL;
	}
	return info;
}

void releaseTCPInfo(TCPInfo *info) {
	if (info) {
		if (info->filename)
			free(info->filename);
		free(info);
	}
}
